package com.binarycat.util.jvm;

import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.ThreadMXBean;
import java.text.DecimalFormat;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.springframework.cache.config.CacheManagementConfigUtils;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.sun.management.OperatingSystemMXBean;

import cn.hutool.cache.CacheUtil;

/**
 * @author jjb
 * @date 2018/08/06
 */
@SuppressWarnings("restriction")
public class SystemInfoUtils {

    private static final OperatingSystemMXBean OSMXB =
        (OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();

    private static final List<GarbageCollectorMXBean> GC_MX_BEAN = ManagementFactory.getGarbageCollectorMXBeans();

    private static final ThreadMXBean THREAD_MX_BEAN = ManagementFactory.getThreadMXBean();

    private static final MemoryMXBean MEMORY_MX_BEAN = ManagementFactory.getMemoryMXBean();

    private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("######0.0");

    private static Cache<String, Object> cache;

    static {
        // 缓存的容量为2,超时时间为10毫秒
        cache = CacheBuilder.newBuilder().maximumSize(2).expireAfterWrite(10, TimeUnit.MILLISECONDS).build();
    }

    /**
     * 获取操作系统名称
     * 
     * @return
     */
    public static String getOsName() {
        // 操作系统
        String osName = System.getProperty("os.name");
        return osName;
    }

    /**
     * 获取系统cpu负载(0到1)
     * 
     * @return 小数
     */
    public static double getSystemCpuLoad() {
        OperatingSystemMXBean osmxb = (OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
        return osmxb.getSystemCpuLoad();
    }

    /**
     * 获取jvm进程负载(0到1)
     * 
     * @return
     * 
     * @return 小数
     */
    public synchronized static double getJvmProcessCpuLoad() {
        String key = "JvmProcessCpuLoad";
        Object obj = cache.getIfPresent(key);
        if (obj == null) {
            // 注意OSMXB.getProcessCpuLoad(),在极短时间间隔内调用两次或数次,
            // 会出现第二次调用的结果不准确的问题,所以此处使用了超时缓存,先从缓存中取,确保多吃调用获取一样的数据
            // 固定时间后再重新调用,获取最新数据
            double processCpuLoad = OSMXB.getProcessCpuLoad();
            cache.put(key, processCpuLoad);
            return processCpuLoad;
        }
        return (double)obj;
    }

    /**
     * 获取总的物理内存
     * 
     * @return 单位M
     */
    public static long getSystemTotalMemorySize() {
        int mb = 1024 * 1024;
        return OSMXB.getTotalPhysicalMemorySize() / mb;
    }

    /**
     * 获取剩余的物理内存
     * 
     * @return 单位M
     */
    public static long getSystemFreePhysicalMemorySize() {
        int mb = 1024 * 1024;
        return OSMXB.getFreePhysicalMemorySize() / mb;
    }

    /**
     * 获取已使用的物理内存
     * 
     * @return 单位M
     */
    public static long getSystemUsedMemory() {
        int mb = 1024 * 1024;
        return (OSMXB.getTotalPhysicalMemorySize() - OSMXB.getFreePhysicalMemorySize()) / mb;
    }

    /**
     * 获取jvm已使用的内存
     * 
     * @return 单位M
     */
    public static long getJvmUsedMemory() {
        int mb = 1024 * 1024;
        // 椎内存使用情况
        MemoryUsage memoryUsage = MEMORY_MX_BEAN.getHeapMemoryUsage();
        return memoryUsage.getUsed() / mb;

    }

    /**
     * 获取jvm的总内存
     * 
     * @return 单位M
     */
    public static long getJvmTotalMemory() {
        int mb = 1024 * 1024;
        // 椎内存使用情况
        MemoryUsage memoryUsage = MEMORY_MX_BEAN.getHeapMemoryUsage();
        // 单位M
        return memoryUsage.getMax() / mb;

    }

    /**
     * 获取jvm的内存使用率
     * 
     * @return 小数
     */
    public static double getJvmMemoryUsageRate() {
        int mb = 1024 * 1024;
        // 椎内存使用情况
        MemoryUsage memoryUsage = MEMORY_MX_BEAN.getHeapMemoryUsage();
        // 单位M
        double maxMemory = memoryUsage.getMax() / mb;
        // 单位M
        double usedMemory = memoryUsage.getUsed() / mb;
        return usedMemory / maxMemory;
    }

    /**
     * 获取jvm的当前线程数
     * 
     * @return
     */
    public static int getJvmThreadCount() {
        return THREAD_MX_BEAN.getThreadCount();
    }

    /**
     * 获取jvm启动以来的线程数的峰值
     * 
     * @return
     */
    public static int getJvmPeakThreadCount() {
        return THREAD_MX_BEAN.getPeakThreadCount();
    }

    /**
     * 获取百分比
     * 
     * @param val
     * @return
     */
    public static String getPercentage(double val) {
        return DECIMAL_FORMAT.format(val * 100) + "%";

    }

    /**
     * 获取GC信息
     * 
     * @param val
     * @return
     */
    public static List<GarbageCollectorMXBean> getGcInfo() {
        GC_MX_BEAN.forEach(collector -> {
            System.out.println(collector.getName());
            System.out.println(collector.getCollectionCount());
            System.out.println(collector.getCollectionTime());
        });
        return GC_MX_BEAN;
    }

    /**
     * Get CPU time in nanoseconds.
     */

    public static long getCurrentThreadCpuTime() {
        return THREAD_MX_BEAN.getCurrentThreadCpuTime();

    }

    /** Get user time in nanoseconds. */

    public static long getCurrentThreadUserTime() {
        return THREAD_MX_BEAN.getCurrentThreadUserTime();

    }
}